#ifndef SESSION_H 
#define SESSION_H 

#include <atomic>
#include <boost/asio/io_context.hpp>
#include <boost/asio/strand.hpp>
#include <iostream>
#include <queue>
#include <mutex>
#include <boost/asio.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>

#include "message_node.hpp"

using boost::asio::ip::tcp;

const int MAX_LENGTH = 64;

class Server;

class Session: public std::enable_shared_from_this<Session>
{
public:
    using ptr = std::shared_ptr<Session>;

    Session(boost::asio::io_context& ioc, Server* server)
    :_socket(ioc)
    ,_server(server) 
    ,_head_parse_done(false)
    ,_strand(ioc.get_executor())
    {
        boost::uuids::uuid uuid = boost::uuids::random_generator()();
        _uuid = boost::uuids::to_string(uuid);
        _recv_head_msg = std::make_shared<MsgNode>(HEAD_TOTAL_LEN);
    };

    tcp::socket& socket() { return _socket; }
    void start();

    std::string uuid() { return _uuid; }
    
    void send(const char* msg, uint16_t len, uint16_t msg_id);

private:
    void handle_read(const boost::system::error_code& error, size_t bytes_transferred,
        std::shared_ptr<Session> self);
    void handle_write(const boost::system::error_code& errorsize_t, size_t bytes_transferred,
        std::shared_ptr<Session> self);

private:
    tcp::socket _socket;
    char _data[MAX_LENGTH];
    Server* _server;
    std::string _uuid;
    std::queue<std::shared_ptr<SendNode>> _send_queue;
    std::mutex _send_queue_lock;

    std::atomic_bool _head_parse_done; // 头信息是否解析完成
    std::shared_ptr<MsgNode> _recv_head_msg; // 接收到的消息的头信息
    std::shared_ptr<RecvNode> _recv__msg; // 接收到的消息

    boost::asio::strand<boost::asio::io_context::executor_type> _strand;  // 保证异步读取缓冲区的串行执行
};


class Task 
{
public:
    using ptr = std::shared_ptr<Task>;

    Task(Session::ptr session, RecvNode::ptr recv_node)
    :_session(session), _recv_node(recv_node) {}

    uint16_t msg_id() { return _recv_node->_msg_id; }

    Session::ptr _session;
    RecvNode::ptr _recv_node;
};

#endif	/* SESSION_H */
